package com.choosefine.paycenter.channel.ccb.api.impl;

import com.alibaba.fastjson.JSONObject;
import com.choosefine.paycenter.channel.ccb.entity.CCBB2BPayReqParams;
import com.choosefine.paycenter.channel.ccb.entity.CCBB2CPayReqParams;
import com.choosefine.paycenter.channel.ccb.utils.encrpt.RSASig;
import com.choosefine.paycenter.pay.api.AbstractPayService;
import com.choosefine.paycenter.pay.dto.PayOrderDto;
import com.choosefine.paycenter.pay.enums.NotifyType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.Map;

/**
 * Comments：建行支付
 * Author：Jay Chang
 * Create Date：2017/4/12
 * Modified By：
 * Modified Date：
 * Why & What is modified：
 * Version：v1.0
 */
@Slf4j
@Service("ccbPayService")
public class CCBPayServiceImpl extends AbstractPayService {
    private final static String CCB_BANK_URL = "https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain";
    private final static String CCB_BANK_B2B_URL = "https://ibsbjstar.ccb.com.cn/app/ccbMain";

    /**建行B2C网银支付用于签名*/
    private static final String B2C_NB_PARAMS = "MERCHANTID={MERCHANTID}&POSID={POSID}&BRANCHID={BRANCHID}&ORDERID={ORDERID}" +
            "&PAYMENT={PAYMENT}&CURCODE={CURCODE}&TXCODE={TXCODE}&REMARK1={REMARK1}&REMARK2={REMARK2}&TYPE=1&PUB={PUB}&GATEWAY={GATEWAY}" +
            "&CLIENTIP={CLIENTIP}&REGINFO={REGINFO}&PROINFO={PROINFO}&REFERER={REFERER}";
    /**建行B2C手机支付用于签名*/
    private static final String B2C_APP_PARAMS = B2C_NB_PARAMS+"&THIRDAPPINFO={THIRDAPPINFO}";
    /**建行B2B网银支付用于签名*/
    private static final String B2B_NB_PARAMS = "MERCHANTID={MERCHANTID}&POSID={POSID}&BRANCHID={BRANCHID}&ORDERID={ORDERID}&PAYMENT=" +
            "{PAYMENT}&CURCODE={CURCODE}&TXCODE={TXCODE}&REMARK1={REMARK1}&REMARK2={REMARK2}";
    /**建行B2C支付页面通知回调参数(不包括签名)*/
    private static final String RETURN_PARAMS = "POSID={POSID}&BRANCHID={BRANCHID}&ORDERID={ORDERID}&PAYMENT={PAYMENT}&CURCODE={CURCODE}&REMARK1={REMARK1}&REMARK2={REMARK2}&SUCCESS={SUCCESS}";
    /**建行B2C网银支付服务器通知回调参数(不包括签名)*/
    private static final String NOTIFY_PARAMS = "POSID={POSID}&BRANCHID={BRANCHID}&ORDERID={ORDERID}&PAYMENT={PAYMENT}&CURCODE={CURCODE}&REMARK1={REMARK1}&REMARK2={REMARK2}&ACC_TYPE={ACC_TYPE}&SUCCESS={SUCCESS}";

    /**建行B2B网银支付页面通知（及服务器通知返回的）参数（不包括签名）*/
    private static final String B2B_NB_RETURN_PARAMS = "{MPOSID}{ORDER_NUMBER}{CUST_ID}{ACC_NO}{ACC_NAME}{AMOUNT}{STATUS}{REMARK1}{REMARK2}{TRAN_FLAG}{TRAN_TIME}{BRANCH_NAME}";

    @Autowired
    private CCBPayConfigStorage ccbPayConfigStorage;

    @PostConstruct
    public void init(){
        setPayConfigStorage(ccbPayConfigStorage);
    }

    @Override
    public String buildRequest(PayOrderDto payOrderDto, String payType) {
        try {
            if (CCBPayType.B2C_NB.getType().equals(payType)) {
                return doProcessB2CNetBankPay(payOrderDto,payType);//建行B2C网银支付
            }else if (CCBPayType.B2B_NB.getType().equals(payType)) {
                return doProcessB2BNetBankPay(payOrderDto,payType);//建行B2B网银支付
            }else if (CCBPayType.B2C_APP.getType().equals(payType)) {
                return doProcessB2CAppPay(payOrderDto,payType);//建行B2C手机支付
            }
        }catch (Exception e){
            throw new RuntimeException(e);
        }
        throw new UnsupportedOperationException("不支持的交易类型:"+payType);
    }



    /**
     * 建行B2C网银支付
     * @param payOrderDto
     * @param payType
     * @return
     */
    private String doProcessB2CNetBankPay(PayOrderDto payOrderDto,String payType){
        //获取B2C网银支付的配置
        JSONObject b2cNB = ccbPayConfigStorage.getB2cNB();
        //创建B2C网银支付请求参数对象
        CCBB2CPayReqParams ccbb2cReqParams = b2cNB.toJavaObject(CCBB2CPayReqParams.class);
        ccbb2cReqParams.setMERCHANTID(ccbPayConfigStorage.getMerchantId());
        ccbb2cReqParams.setBRANCHID(ccbPayConfigStorage.getCommon().getString("BRANCHID"));
        ccbb2cReqParams.setCURCODE(ccbPayConfigStorage.getCommon().getString("CURCODE"));
        //设置支付订单号、支付金额、商户ID
        ccbb2cReqParams.setORDERID(payOrderDto.getOrderId());
        ccbb2cReqParams.setPAYMENT(payOrderDto.getAmount().toString());
        try {
            Map<String, String> map = BeanUtils.describe(ccbb2cReqParams);
            //用于签名的uri
            String srcUriStr = UriComponentsBuilder.fromUriString(B2C_NB_PARAMS).buildAndExpand(map).toUriString();
            //请求参数签名
            String signStr = this.createSign(srcUriStr);
            //PUB仅参与签名，不做参数传递(因此最终跳转的url里需要删除PUB参数)
            String gotoBankUrl = CCB_BANK_URL + "?" + srcUriStr.replaceFirst("&PUB=\\w+", "")+ "&MAC=" + signStr;
            log.info("生成跳转建行B2C支付url：" + gotoBankUrl);
            return gotoBankUrl;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    /**
     * 建行B2C APP支付
     * @param payOrderDto
     * @param payType
     * @return
     */
    private String doProcessB2CAppPay(PayOrderDto payOrderDto,String payType) {
        JSONObject b2cApp = ccbPayConfigStorage.getB2cApp();
        CCBB2CPayReqParams ccbb2cReqParams = b2cApp.toJavaObject(CCBB2CPayReqParams.class);
        ccbb2cReqParams.setMERCHANTID(ccbPayConfigStorage.getMerchantId());
        ccbb2cReqParams.setBRANCHID(ccbPayConfigStorage.getCommon().getString("BRANCHID"));
        ccbb2cReqParams.setCURCODE(ccbPayConfigStorage.getCommon().getString("CURCODE"));
        //设置支付订单号、支付金额、
        ccbb2cReqParams.setORDERID(payOrderDto.getOrderId());
        ccbb2cReqParams.setPAYMENT(payOrderDto.getAmount().toString());
        try {
            Map<String, String> map = BeanUtils.describe(ccbb2cReqParams);
            //用于签名的uri
            String srcUriStr = UriComponentsBuilder.fromUriString(B2C_APP_PARAMS).buildAndExpand(map).toUriString();
            //请求参数签名
            String signStr = this.createSign(srcUriStr);
            //PUB仅参与签名，不做参数传递(因此最终跳转的url里需要删除PUB参数)
            String gotoBankUrl = CCB_BANK_URL + "?" + srcUriStr.replaceFirst("&PUB=\\w+", "") + "&MAC=" + signStr;
            log.info("生成跳转建行B2C支付url：" + gotoBankUrl);
            return gotoBankUrl;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    /**
     * 建行B2B网银支付
     * @param payOrderDto
     * @param payType
     * @return
     */
    private String doProcessB2BNetBankPay(PayOrderDto payOrderDto,String payType) {
        JSONObject b2bNB = ccbPayConfigStorage.getB2bNB();
        CCBB2BPayReqParams ccbb2bPayReqParams = b2bNB.toJavaObject(CCBB2BPayReqParams.class);
        ccbb2bPayReqParams.setMERCHANTID(ccbPayConfigStorage.getMerchantId());
        ccbb2bPayReqParams.setBRANCHID(ccbPayConfigStorage.getCommon().getString("BRANCHID"));
        ccbb2bPayReqParams.setCURCODE(ccbPayConfigStorage.getCommon().getString("CURCODE"));
        //设置支付订单ID,支付金额
        ccbb2bPayReqParams.setORDERID(payOrderDto.getOrderId());
        ccbb2bPayReqParams.setPAYMENT(payOrderDto.getAmount().toString());
        try {
            Map<String, String> map = BeanUtils.describe(ccbb2bPayReqParams);
            //用于签名的uri
            String tmpStr = UriComponentsBuilder.fromUriString(B2B_NB_PARAMS).buildAndExpand(map).toUriString();
            log.info("用于签名的源串：{}", tmpStr);
            //请求参数签名
            String signStr = this.createSign(tmpStr);
            String gotoBankUrl = CCB_BANK_B2B_URL + "?" + tmpStr + "&MAC=" + signStr;
            log.info("生成跳转建行B2B支付url：" + gotoBankUrl);
            return gotoBankUrl;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean verifySign(Map<String, String> params, String sign,String payType, NotifyType notifyType) {
        RSASig rsaSig = new RSASig();
        rsaSig.setPublicKey(getPayConfigStorage().getPublicKey(CCBPayType.valueOf(payType.toUpperCase())));
        if(CCBPayType.B2B_NB.getType().equalsIgnoreCase(payType)){
            String notifyParams = B2B_NB_RETURN_PARAMS;
            String srcUri = UriComponentsBuilder.fromUriString(notifyParams).buildAndExpand(params).toUriString();
            try {
                return rsaSig.verifySigature(sign,srcUri.getBytes("GBK"));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }else {
            String notifyParams = NOTIFY_PARAMS;
            if (NotifyType.RETURN.equals(notifyType)) {
                notifyParams = RETURN_PARAMS;
            } else {
                notifyParams = NOTIFY_PARAMS;
            }
            String srcUri = UriComponentsBuilder.fromUriString(notifyParams).buildAndExpand(params).toUriString();
            return rsaSig.verifySigature(sign,srcUri);
        }
    }

    @Override
    public PayOrderDto getPayOrderFromBackParam(Map<String, String> params, String payType) {
        PayOrderDto payOrderDto = null;
        //若是建行B2B支付反馈
        if(CCBPayType.B2B_NB.getType().equalsIgnoreCase(payType)){
            payOrderDto  = new PayOrderDto(params.get("ORDER_NUMBER"), BigDecimal.valueOf(Double.valueOf(params.get("AMOUNT"))));
        }else {
            payOrderDto = new PayOrderDto(params.get("ORDERID"), BigDecimal.valueOf(Double.valueOf(params.get("PAYMENT"))));
        }
        return payOrderDto;
    }

    @Override
    public boolean verifySign(Map<String, String> params, String sign, String payType) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Map orderInfo(PayOrderDto order) {
        throw new UnsupportedOperationException();
    }

    @Override
    public PayOrderDto getPayOrderFromBackParam(Map<String, String> params) {
        throw new UnsupportedOperationException();
    }
}

